/*
 * PreparedStatement.java
 *
 * Created on September 24, 2004, 3:58 PM
 */

package com.absisgroup.nsc.utilities;

import java.io.InputStream;
import java.io.Reader;
import java.sql.NClob;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;

/**
 *
 * @author  hue
 */
public class DBPreparedStatement implements java.sql.PreparedStatement {
    private long sqlId;
    private boolean bKeepParams;
    private Hashtable htParams = new Hashtable();
    private String strQuery;
    private java.sql.PreparedStatement pStmt;
    private String logFile;
    private Date startTime;
    private String sessionId;
    
    /** Creates a new instance of PreparedStatement */
    public DBPreparedStatement(final java.sql.PreparedStatement _pStmt, final String _strQuery, final String _sqlLogfile, final String _sessionId) {
        pStmt = _pStmt;
        strQuery = _strQuery;
        logFile = _sqlLogfile;
        bKeepParams = (logFile != null);
        sessionId = _sessionId;
        sqlId = ++DBConnection.sqlId;
    }
    
    public void forceKeepParams(final boolean b) {
        bKeepParams = b;
    }
    
    @Override
    public boolean execute() throws java.sql.SQLException {
        try {
            saveSQLStatement();
            return pStmt.execute();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public boolean execute(final String sql) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.execute(sql);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public boolean execute(final String sql, final int autoGeneratedKeys) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.execute(sql,autoGeneratedKeys);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public boolean execute(final String sql, final String[] columnNames) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.execute(sql,columnNames);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public boolean execute(final String sql, final int[] columnIndexes) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.execute(sql,columnIndexes);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int[] executeBatch() throws java.sql.SQLException {
        try {
            saveSQLStatement();
            return pStmt.executeBatch();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public java.sql.ResultSet executeQuery() throws java.sql.SQLException {
        try {
            saveSQLStatement();
            return pStmt.executeQuery();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public java.sql.ResultSet executeQuery(final String sql) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.executeQuery(sql);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int executeUpdate() throws java.sql.SQLException {
        try {
            saveSQLStatement();
            return pStmt.executeUpdate();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int executeUpdate(final String sql) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.executeUpdate(sql);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int executeUpdate(final String sql, final int autoGeneratedKeys) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.executeUpdate(sql,autoGeneratedKeys);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int executeUpdate(final String sql, final String[] columnNames) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.executeUpdate(sql,columnNames);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int executeUpdate(final String sql, final int[] columnIndexes) throws java.sql.SQLException {
        try {
            strQuery = sql;
            saveSQLStatement();
            return pStmt.executeUpdate(sql,columnIndexes);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public java.sql.Connection getConnection() throws java.sql.SQLException {
        try {
            return pStmt.getConnection();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int getFetchDirection() throws java.sql.SQLException {
        try {
            return pStmt.getFetchDirection();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int getFetchSize() throws java.sql.SQLException {
        try {
            return pStmt.getFetchSize();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public java.sql.ResultSet getGeneratedKeys() throws java.sql.SQLException {
        try {
            return pStmt.getGeneratedKeys();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int getMaxFieldSize() throws java.sql.SQLException {
        try {
            return pStmt.getMaxFieldSize();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int getMaxRows() throws java.sql.SQLException {
        try {
            return pStmt.getMaxRows();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public java.sql.ResultSetMetaData getMetaData() throws java.sql.SQLException {
        try {
            return pStmt.getMetaData();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public boolean getMoreResults() throws java.sql.SQLException {
        try {
            return pStmt.getMoreResults();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public boolean getMoreResults(final int current) throws java.sql.SQLException {
        try {
            return pStmt.getMoreResults(current);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public java.sql.ParameterMetaData getParameterMetaData() throws java.sql.SQLException {
        try {
            return pStmt.getParameterMetaData();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int getQueryTimeout() throws java.sql.SQLException {
        try {
            return pStmt.getQueryTimeout();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public java.sql.ResultSet getResultSet() throws java.sql.SQLException {
        try {
            return pStmt.getResultSet();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int getResultSetConcurrency() throws java.sql.SQLException {
        try {
            return pStmt.getResultSetConcurrency();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int getResultSetHoldability() throws java.sql.SQLException {
        try {
            return pStmt.getResultSetHoldability();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public int getResultSetType() throws java.sql.SQLException {
        try {
            return pStmt.getResultSetType();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public int getUpdateCount() throws java.sql.SQLException {
        try {
            return pStmt.getUpdateCount();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public java.sql.SQLWarning getWarnings() throws java.sql.SQLException {
        try {
            return pStmt.getWarnings();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setBigDecimal(final int parameterIndex, final java.math.BigDecimal x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setBigDecimal(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setBoolean(final int parameterIndex, final boolean x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setBoolean(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setByte(final int parameterIndex, final byte x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Byte(x));
            pStmt.setByte(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setBytes(final int parameterIndex, final byte[] x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setBytes(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setDate(final int parameterIndex, final java.sql.Date x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setDate(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setDate(final int parameterIndex, final java.sql.Date x, final java.util.Calendar cal) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setDate(parameterIndex,x,cal);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setDouble(final int parameterIndex, final double x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Double(x));
            pStmt.setDouble(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setFloat(final int parameterIndex, final float x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Float(x));
            pStmt.setFloat(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setInt(final int parameterIndex, final int x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Integer(x));
            pStmt.setInt(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setLong(final int parameterIndex, final long x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Long(x));
            pStmt.setLong(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    public void setLong(final int parameterIndex, final Long x) throws java.sql.SQLException {
        this.setBigDecimal(parameterIndex, (x == null ? null : new java.math.BigDecimal(x.longValue())));
    }
    
    @Override
    public void setTime(final int parameterIndex, final java.sql.Time x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setTime(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setTime(final int parameterIndex, final java.sql.Time x, final java.util.Calendar cal) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setTime(parameterIndex,x,cal);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setObject(final int parameterIndex, final Object x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setObject(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setObject(parameterIndex,x,targetSqlType);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setObject(parameterIndex,x,targetSqlType,scale);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setRef(final int i, final java.sql.Ref x) throws java.sql.SQLException {
        try {
            keepParam(i, x);
            pStmt.setRef(i,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setShort(final int parameterIndex, final short x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, new Short(x));
            pStmt.setShort(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setString(final int parameterIndex, final String x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setString(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setTimestamp(final int parameterIndex, final java.sql.Timestamp x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setTimestamp(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setTimestamp(final int parameterIndex, final java.sql.Timestamp x, final java.util.Calendar cal) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setTimestamp(parameterIndex,x,cal);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setURL(final int parameterIndex, final java.net.URL x) throws java.sql.SQLException {
        try {
            keepParam(parameterIndex, x);
            pStmt.setURL(parameterIndex,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
        public void setNull(final int parameterIndex, final int sqlType) throws java.sql.SQLException {
        try {
            pStmt.setNull(parameterIndex,sqlType);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setNull(final int paramIndex, final int sqlType, final String typeName) throws java.sql.SQLException {
        try {
            pStmt.setNull(paramIndex,sqlType,typeName);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }

    @Override
    public void setArray(final int i, final java.sql.Array x) throws java.sql.SQLException {
        try {
            pStmt.setArray(i,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setAsciiStream(final int parameterIndex, final java.io.InputStream x, final int length) throws java.sql.SQLException {
        try {
            pStmt.setAsciiStream(parameterIndex, x,length);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setBinaryStream(final int parameterIndex, final java.io.InputStream x, final int length) throws java.sql.SQLException {
        try {
            pStmt.setBinaryStream(parameterIndex,x,length);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setBlob(final int i, final java.sql.Blob x) throws java.sql.SQLException {
        try {
            pStmt.setBlob(i,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setCharacterStream(final int parameterIndex, final java.io.Reader reader, final int length) throws java.sql.SQLException {
        try {
            pStmt.setCharacterStream(parameterIndex,reader,length);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setClob(final int i, final java.sql.Clob x) throws java.sql.SQLException {
        try {
            pStmt.setClob(i,x);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setCursorName(final String name) throws java.sql.SQLException {
        try {
            pStmt.setCursorName(name);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setEscapeProcessing(final boolean enable) throws java.sql.SQLException {
        try {
            pStmt.setEscapeProcessing(enable);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setFetchDirection(final int direction) throws java.sql.SQLException {
        try {
            pStmt.setFetchDirection(direction);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setFetchSize(final int rows) throws java.sql.SQLException {
        try {
            pStmt.setFetchSize(rows);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setMaxFieldSize(final int max) throws java.sql.SQLException {
        try {
            pStmt.setMaxFieldSize(max);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setMaxRows(final int max) throws java.sql.SQLException {
        try {
            pStmt.setMaxRows(max);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setQueryTimeout(final int seconds) throws java.sql.SQLException {
        try {
            pStmt.setQueryTimeout(seconds);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void setUnicodeStream(final int parameterIndex, final java.io.InputStream x, final int length) throws java.sql.SQLException {
        try {
            pStmt.setUnicodeStream(parameterIndex,x,length);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void addBatch() throws java.sql.SQLException {
        try {
            pStmt.addBatch();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void addBatch(final String sql) throws java.sql.SQLException {
        try {
            pStmt.addBatch(sql);
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void cancel() throws java.sql.SQLException {
        try {
            pStmt.cancel();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void clearBatch() throws java.sql.SQLException {
        try {
            pStmt.clearBatch();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void clearParameters() throws java.sql.SQLException {
        try {
            pStmt.clearParameters();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void clearWarnings() throws java.sql.SQLException {
        try {
            pStmt.clearWarnings();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //close the satement if there's an error
            this.close();
            throw ex;
        }
    }
    
    @Override
    public void close() throws java.sql.SQLException {
        try {
            pStmt.close();
        }
        catch(java.sql.SQLException _ex) {
            final DBSQLException ex = new DBSQLException(_ex, getSQLStatement());
            //don't close the satement in this case :).
            throw ex;
        }
        release();
    }
    
    /**
     * Release all allocated resources.
     */
    private void release() {
        try {
            pStmt = null;
            htParams.clear();
            htParams = null;
        }
        catch (Exception ex) {
            System.out.println(ex);
        }
        saveExecutionTime();
    }

    protected void keepParam(final int parameterIndex, final Object x) throws java.sql.SQLException {
        if(x != null && bKeepParams) {
            htParams.put(String.valueOf(parameterIndex), x);
        }
    }
    
    private void saveSQLStatement() {
        if(!bKeepParams || logFile == null) {
            return;
        }
        startTime = new Date();
        try {
            final StringBuffer sb = new StringBuffer("\r\n-- [SQL_C] [");
            sb.append(sessionId);
            sb.append(",sqlId=");
            sb.append(sqlId);
            sb.append("][");
            sb.append(Util.toString(startTime, "dd/MM/yyyy HH:mm:ss"));
            sb.append("]\r\n");
            sb.append(getSQLStatement());
            sb.append(';');
            Util.writeFile(logFile, sb.toString().getBytes(), true);
        }
        catch(Exception ex) {
            logFile = null;
        }
    }
    
    private void saveExecutionTime() {
        if(!bKeepParams || startTime == null || logFile == null) {
            return;
        }
        try {
            final StringBuffer sb = new StringBuffer("\r\n-- [SQL_R] [");
            sb.append(sessionId);
            sb.append(",sqlId=");
            sb.append(sqlId);
            sb.append("][");
            sb.append(Util.calculateDuration(startTime, new java.util.Date()));
            sb.append(']');
            Util.writeFile(logFile, sb.toString().getBytes(), true);
        }
        catch(Exception ex) {
            logFile = null;
        }
    }
    
    public String getSQLStatement() {
        final ArrayList alIndexes = new ArrayList();
        final int length = strQuery.length();
        for(int i=0; i<length; i++) {
            if(strQuery.charAt(i) == '?') {
                alIndexes.add(String.valueOf(i));
            }
        }
        //
        StringBuffer sb = new StringBuffer(strQuery);
        for(int i=alIndexes.size()-1; i>=0; i--) {
            final Object value = htParams.get(String.valueOf(i+1));
            String strValue = "";
            if(value == null) {
                strValue = "null";
            }
            else if(value instanceof java.lang.String) {
                strValue = "'" + Util.replace((String)value, "'", "''") + "'";
            }
            else if(value instanceof java.util.Date) {
                final String dateString = Util.toString((java.util.Date)value ,"dd/MM/yyyy HH:mm:ss");
                strValue = "to_date('" + dateString + "', 'dd/mm/yyyy hh24:mi:ss')";
            }
            else {
                strValue = value.toString();
            }
            final int index = Integer.parseInt((String)alIndexes.get(i));
            sb = sb.replace(index, index+1, strValue);
        }

        return sb.toString();
    }

    @Override
    public void setRowId(int parameterIndex, RowId x) throws SQLException {
        pStmt.setRowId(parameterIndex, x);
    }

    @Override
    public void setNString(int parameterIndex, String value) throws SQLException {
        pStmt.setNString(parameterIndex, value);
    }

    @Override
    public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
        pStmt.setNCharacterStream(parameterIndex, value, length);
    }

    @Override
    public void setNClob(int parameterIndex, NClob value) throws SQLException {
        pStmt.setNClob(parameterIndex, value);
    }

    @Override
    public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
        pStmt.setClob(parameterIndex, reader, length);
    }

    @Override
    public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
        pStmt.setBlob(parameterIndex, inputStream, length);
    }

    @Override
    public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
        pStmt.setNClob(parameterIndex, reader, length);
    }

    @Override
    public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
        pStmt.setSQLXML(parameterIndex, xmlObject);
    }

    @Override
    public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
        pStmt.setAsciiStream(parameterIndex, x, length);
    }

    @Override
    public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
        pStmt.setBinaryStream(parameterIndex, x, length);
    }

    @Override
    public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
        pStmt.setCharacterStream(parameterIndex, reader, length);
    }

    @Override
    public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
        pStmt.setAsciiStream(parameterIndex, x);
    }

    @Override
    public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
        pStmt.setBinaryStream(parameterIndex, x);
    }

    @Override
    public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
        pStmt.setCharacterStream(parameterIndex, reader);
    }

    @Override
    public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
        pStmt.setNCharacterStream(parameterIndex, value);
    }

    @Override
    public void setClob(int parameterIndex, Reader reader) throws SQLException {
        pStmt.setClob(parameterIndex, reader);
    }

    @Override
    public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
        pStmt.setBlob(parameterIndex, inputStream);
    }

    @Override
    public void setNClob(int parameterIndex, Reader reader) throws SQLException {
        pStmt.setNClob(parameterIndex, reader);
    }

    @Override
    public boolean isClosed() throws SQLException {
        return pStmt.isClosed();
    }

    @Override
    public void setPoolable(boolean poolable) throws SQLException {
        pStmt.setPoolable(poolable);
    }

    @Override
    public boolean isPoolable() throws SQLException {
        return pStmt.isPoolable();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return pStmt.unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return pStmt.isWrapperFor(iface);
    }
}
